package com.example.algorithm.prefixSum;

import java.util.Arrays;

/**
 * 给定一个二维矩阵 matrix，以下类型的多个请求：
 * 计算其子矩形范围内元素的总和，该子矩阵的 左上角 为 (row1, col1) ，右下角 为 (row2, col2) 。
 * <p>
 * 实现 NumMatrix 类：
 * NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
 * int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1) 、右下
 * 角 (row2, col2) 所描述的子矩阵的元素 总和 。
 * <p>
 * 示例 1：
 * 输入:
 * ["NumMatrix","sumRegion","sumRegion","sumRegion"]
 * [[[[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]],
 * [2,1,4,3],[1,1,2,2],[1,2,2,4]]
 * 输出:
 * [null, 8, 11, 12]
 * <p>
 * 解释:
 * NumMatrix numMatrix = new NumMatrix([[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]);
 * numMatrix.sumRegion(2, 1, 4, 3); // return 8 (红色矩形框的元素总和)
 * numMatrix.sumRegion(1, 1, 2, 2); // return 11 (绿色矩形框的元素总和)
 * numMatrix.sumRegion(1, 2, 2, 4); // return 12 (蓝色矩形框的元素总和)
 */
public class Leetcode304_SumRegion {

    /**
     * 解法二：二维前缀和
     * preSums[i][j] 表示 以 matrix[0][0]为左上角，matrix[i][j]为右下角的矩阵的和
     */
    static class NumMatrix2 {
        int[][] preSums;
        public NumMatrix2(int[][] matrix) {
            int m = matrix.length, n = matrix[0].length;
            preSums = new int[m + 1][n + 1];
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= n; j++) {
                    preSums[i][j] = preSums[i - 1][j] + preSums[i][j - 1] - preSums[i - 1][j - 1] + matrix[i - 1 ][j - 1];
                }
            }

        }

        public int sumRegion(int row1, int col1, int row2, int col2) {
            return preSums[row2 + 1][col2 + 1] - preSums[row1][col2 + 1] - preSums[row2 + 1][col1] + preSums[row1][col1];
        }
    }

    /**
     * 解法一：一维前缀和
     * preSums[i] 为 matrix[i] 的前缀和数组
     *    即 preSums[i][j] = matrix[i][0] + matrix[i][1] + matrix[i][2] + ... + matrix[i][j]
     *
     * 所以有sumRegion(row1, col1, row2, col2) = sum(preSums[i][col2 + 1] - preSums[i][col1]) 其中 row1 <= i <= row2
     */
    static class NumMatrix {
        int[][] preSums; // matrix[i] 的前缀和数组
        public NumMatrix(int[][] matrix) {
            int m = matrix.length, n = matrix[0].length;
            preSums = new int[m][n + 1];
            for (int i = 0; i < m; i++) {
                for (int j = 1; j <= n; j++) {
                    preSums[i][j] = preSums[i][j - 1] + matrix[i][j - 1];
                }
            }
        }

        public int sumRegion(int row1, int col1, int row2, int col2) {
            int res = 0;
            for (int i = row1; i <= row2; i++)
                res += preSums[i][col2 + 1] - preSums[i][col1];
            return res;
        }
    }

    public static void main(String[] args) {
        int[][] matrix = {
                {3, 0, 1, 4, 2},
                {5, 6, 3, 2, 1},
                {1, 2, 0, 1, 5},
                {4, 1, 0, 1, 7},
                {1, 0, 3, 0, 5}};
//        NumMatrix numMatrix = new NumMatrix(matrix);
//        System.out.println(numMatrix.sumRegion(2, 1, 4, 3)); // return 8 (红色矩形框的元素总和)
//        System.out.println(numMatrix.sumRegion(1, 1, 2, 2)); // return 11 (绿色矩形框的元素总和)
//        System.out.println(numMatrix.sumRegion(1, 2, 2, 4)); // return 12 (蓝色矩形框的元素总和)

        NumMatrix2 numMatrix2 = new NumMatrix2(matrix);
        System.out.println(numMatrix2.sumRegion(2, 1, 4, 3)); // return 8 (红色矩形框的元素总和)
        System.out.println(numMatrix2.sumRegion(1, 1, 2, 2)); // return 11 (绿色矩形框的元素总和)
        System.out.println(numMatrix2.sumRegion(1, 2, 2, 4)); // return 12 (蓝色矩形框的元素总和)
    }
}
